<font size=18><a href="~audio/Ch14/14fig006.au"><img src="bckgrnds/icons/audio.gif" align=sidebar></a>Figure 14.6 - End-of-file key combinations for various popular computer systems.<i></i><i></i></font><br>
<img src="graphics/ch14/fig14006.gif" ><br>
</page>
<page>
<font size=18><a href="~audio/Ch14/14fig010.au"><img src="bckgrnds/icons/audio.gif" align=sidebar></a>Figure 14.10 - C++'s view of a random access file.<img src="graphics/ch14/fig14010.gif" ></font><br>
a) Ultimately, all data items processed by a computer are reduced to
combinations of________and ________.<br>
b) The smallest data item a computer can process is called a ________.<br>
c) A ________ is a group of related records.<br>
d) Digits, letters, and special symbols are referred to as ________.<br>
e) A group of related files is called a ________.<br>
f) Member function ________ of the file stream classes <b>fstream</b>, <b>ifstream</b>,
and <b>ofstream</b> closes a file.<br>
g) The <b>istream</b> member function ________ reads a character from the
specified stream.<br>
<foreign name="answers" url="^Answers::c:s0p0">
</page>
<page pagename="Exercise 14.1">
h) The <b>istream</b> member functions ________ and ________ read a line from
the specified stream.<br>
i) Member function ________ of the file stream classes <b>fstream</b>, <b>ifstream</b>,
and <b>ofstream</b> opens a file.<br>
j) The <b>istream</b> member function ________ is normally used when reading
data from a file in random access applications.<br>
k) Member functions ________ and ________ of the <b>istream</b> and <b>ostream</b>
classes set the appropriate position pointer to a specific location in an input or
output stream respectively.<br>
<foreign name="answers" url="^Answers::c:s0p0">
<br>
<br>
</page>
<page pagename="Exercise 14.2">
<b>Exercise 14.2</b><br>
State which of the following are true and which are false (for those that are false,
explain why):<br>
a) Member function <b>read</b> cannot be used to read data from the input object <b>cin</b>.<br>
b) The programmer must explicitly create the <b>cin</b>, <b>cout</b>, <b>cerr</b>, and <b>clog</b> objects.<br>
c) A program must explicitly call function <b>close</b> to close a file associated with
an <b>ifstream</b>, <b>ofstream</b>, or <b>fstream</b> object.<br>
d) If the file position pointer points to a location in a sequential file other than
the beginning of the file, the file must be closed and reopened to read from the
beginning of the file.<br>
e) The <b>ostream</b> member function <b>write</b> can write to standard output stream
cout.<br>
<foreign name="answers" url="^Answers::c:s0p2">
</page>
<page pagename="Exercise 14.2">
f) Data in sequential access files is always updated without overwriting nearby
data.<br>
g) It is not necessary to search through all the records in a random access file to
find a specific record.<br>
h) Records in random access files must be of uniform length.<br>
i) Member functions <b>seekp</b> and <b>seekg</b> must seek relative to the beginning of a
file.<br>
<foreign name="answers" url="^Answers::c:s0p2">
<br>
<br>
</page>
<page pagename="Exercise 14.3">
<b>Exercise 14.3</b><br>
Assume that each of the following statements applies to the same program.<br>
a) Write a statement that opens file "<b>oldmast.dat</b>" for input; use <b>ifstream</b>
object <b>inOldMaster</b>.<br>
b) Write a statement that opens file "<b>trans.dat</b>" for input; use <b>ifstream</b> object
<b>inTransaction</b>.<br>
c) Write a statement that opens file "<b>newmast.dat</b>" for output (and creation);
use <b>ofstream</b> object <b>outNewMaster</b>.<br>
e) Write a statement that reads a record from the file "<b>oldmast.dat</b>". The
record consists of integer <b>accountNum</b>, string <b>name</b>, and floating point
<b>currentBalance</b>; use <b>ifstream</b> object <b>inOldMaster</b>.<br>
<foreign name="answers" url="^Answers::c:s0p4">
</page>
<page pagename="Exercise 14.3">
f) Write a statement that reads a record from the file "<b>trans.dat</b>". The record
consists of integer <b>accountNum</b> and floating point <b>dollarAmount</b>; use <b>ifstream</b>
object <b>inTransaction</b>.<br>
g) Write a statement that writes a record to the file "<b>newmast.dat</b>". The record
consists of integer <b>accountNum</b>, string <b>name</b>, and floating point
<b>currentBalance</b>; use <b>ofstream</b> object <b>outNewMaster</b>.<br>
<foreign name="answers" url="^Answers::c:s0p4">
<br>
<br>
</page>
<page pagename="Exercise 14.4">
<b>Exercise 14.4</b><br>
Find the error and show how to correct it in each of the following. <br>
a) File "<b>payables.dat</b>" referred to by <b>ofstream</b> object <b>outPayable</b> has not been
opened.<br>
<font size=2><br></font><font size=11><pre>
outPayable << account << company << amount << endl;<p>
</pre></font>
b) The following statement should read a record from the file "<b>payables.dat</b>".
The <b>ifstream</b> object <b>inPayable</b> refers to this file, and <b>istream</b> object
<b>inReceivable</b> refers to the file "<b>receivables.dat</b>".<br>
<font size=2><br></font><font size=11><pre>
inReceivable >> account >> company >> amount;<p>
</pre></font>
c) The file "<b>tools.dat</b>" should be opened to add data to the file without
discarding the current data.<br>
<foreign name="answers" url="^Answers::c:s0p5">
</page>
<page pagename="Exercise 14.4">
<font size=2><br></font><font size=11><pre>
ofstream outTools( "tools.dat", ios::out );<p>
</pre></font>
<foreign name="answers" url="^Answers::c:s0p5">
<br>
<br>
</page>
<page pagename="Exercise 14.5">
<b>Exercise 14.5</b><br>
Fill in the blanks in each of the following:<br>
a) Computers store large amounts of data on secondary storage devices as
______.<br>
b) A ________ is composed of several fields.<br>
c) A field that may contain only digits, letters, and blanks is called
an________ field.<br>
d) To facilitate the retrieval of specific records from a file, one field in each
record is chosen as a ________.<br>
e) The vast majority of information stored in computer systems is stored in
________ files.<br>
f) A group of related characters that conveys meaning is called a ________.<br>
</page>
<page pagename="Exercise 14.5">
g) The standard stream objects declared by header file <b><iostream.h></b> are
_______ , _______ , _______ , and_______ .<br>
h) The <b>ostream</b> member function ________ outputs a character to the
specified stream.<br>
i) The <b>ostream</b> member function ________ is generally used to write data to
a randomly accessed file.<br>
j) The <b>istream</b> member function ________ repositions the file position
pointer in a file.<br>
<br>
<br>
</page>
<page pagename="Exercise 14.6">
<b>Exercise 14.6</b><br>
State which of the following are true and which are false (and for those that are
false, explain why):<br>
a) The impressive functions performed by computers essentially involve the
manipulation of zeros and ones.<br>
b) People prefer to manipulate bits instead of characters and fields because bits
are more compact.<br>
c) People specify programs and data items as characters; computers then
manipulate and process these characters as groups of zeros and ones.<br>
d) A person's 5-digit zip code is an example of a numeric field.<br>
e) A person's street address is generally considered to be an alphabetic field in
computer applications.<br>
</page>
<page pagename="Exercise 14.6">
f) Data items represented in computers form a data hierarchy in which data
items become larger and more complex as we progress from fields to characters
to bits, etc.<br>
g) A record key identifies a record as belonging to a particular field.<br>
h) Most organizations store all their information in a single file to facilitate
computer processing.<br>
i) Each statement that processes a file in a C++ program explicitly refers to that
file by name.<br>
j) When a program creates a file, the file is automatically retained by the
computer for future reference.<br>
<br>
<br>
</page>
<page pagename="Exercise 14.7">
<b>Exercise 14.7</b><br>
<a href="^Exercises::c:s0p4"><img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.3</a> asked the reader to write a series of single statements. Actually,
these statements form the core of an important type of file processing program,
namely, a file-matching program. In commercial data processing, it is common
to have several files in each application system. In an accounts receivable
system, for example, there is generally a master file containing detailed
information about each customer such as the customer's name, address,
arrangements, and possibly a condensed history of recent purchases and cash
payments.<br>
As transactions occur (i.e., sales are made and cash payments arrive in the mail),
they are entered into a file. At the end of each business period (i.e., a month for<br>
<foreign name="answers" url="^Answers::c:s0p6">
</page>
<page pagename="Exercise 14.7">
some companies, a week for others, and a day in some cases) the file of
transactions (called "<b>trans.dat</b>" in <a href="^Exercises::c:s0p4"><img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.3</a>) is applied to the master file
(called "<b>oldmast.dat</b>" in <a href="^Exercises::c:s0p4"><img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.3</a>), thus updating each account's record of
purchases and payments. During an updating run, the master file is rewritten as a
new file ("<b>newmast.dat</b>"), which is then used at the end of the next business
period to begin the updating process again.<br>
File-matching programs must deal with certain problems that do not exist in
single-file programs. For example, a match does not always occur. A customer
on the master file may not have made any purchases or cash payments in the
current business period, and therefore no record for this customer will appear on
the transaction file. Similarly, a customer who did make some purchases or cash<br>
<foreign name="answers" url="^Answers::c:s0p6">
</page>
<page pagename="Exercise 14.7">
payments may have just moved to this community, and the company may not
have had a chance to create a master record for this customer.<br>
Use the statements written in <a href="^Exercises::c:s0p4"><img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.3</a> as a basis for writing a complete file-
matching accounts receivable program. Use the account number on each file as
the record key for matching purposes. Assume that each file is a sequential file
with records stored in increasing order by account number.<br>
When a match occurs (i.e., records with the same account number appear on
both the master file and the transaction file), add the dollar amount on the
transaction file to the current balance on the master file, and write the
"<b>newmast.dat</b>" record. (Assume that purchases are indicated by positive
amounts on the transaction file, and that payments are indicated by negative
amounts.) When there is a master record for a particular account but no<br>
<foreign name="answers" url="^Answers::c:s0p6">
</page>
<page pagename="Exercise 14.7">
corresponding transaction record, merely write the master record to
"<b>newmast.dat</b>". When there is a transaction record but no corresponding
master record, print the message "<b>Unmatched transaction record for account
number</b>" (fill in the account number from the transaction record).<br>
<foreign name="answers" url="^Answers::c:s0p6">
<br>
</page>
<page pagename="Exercise 14.8">
<b>Exercise 14.8</b><br>
After writing the program of <a href="^Exercises::c:s0p12"><img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.7</a>, write a simple program to create
some test data for checking out the program. Use the following sample account
data: <img src="graphics/ch14/ex1408a.gif" ><br>
</page>
<page pagename="Exercise 14.8">
<img src="graphics/ch14/ex1408b.gif" ><br>
<br>
</page>
<page pagename="Exercise 14.9">
<b>Exercise 14.9</b><br>
Run the program of<a href="^Exercises::c:s0p12"> <img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.7</a> using the files of test data created in<a href="^Exercises::c:s0p16"> <img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise
14.8</a>. Print the new master file. Check that the accounts have been updated
correctly.<br>
<br>
<br>
</page>
<page pagename="Exercise 14.10">
<b>Exercise 14.10</b><br>
It is possible (actually common) to have several transaction records with the
same record key. This occurs because a particular customer might make several
purchases and cash payments during a business period. Rewrite your accounts
receivable file-matching program of<a href="^Exercises::c:s0p12"> <img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.7</a> to provide for the possibility
of handling several transaction records with the same record key. Modify the test
data of<a href="^Exercises::c:s0p16"> <img src="bckgrnds/icons/exercise.gif" align=sidebar>Exercise 14.8</a> to include the following additional transaction records:<br>
</page>
<page pagename="Exercise 14.10">
<img src="graphics/ch14/ex14010.gif" ><br>
<br>
<br>
</page>
<page pagename="Exercise 14.11">
<b>Exercise 14.11</b><br>
Write a series of statements that accomplish each of the following. Assume the
structure<br>
<font size=2><br></font><font size=11><pre>
<spacer width=20 height=1>struct person {<p>
<spacer width=20 height=1> char lastName[15];<p>
<spacer width=20 height=1> char firstName[15];<p>
<spacer width=20 height=1> char age[2];<p>
<spacer width=20 height=1>};<p>
</pre></font>
has been defined, and that the random access file has been opened properly.<br>
a) Initialize the file "<b>nameage.dat</b>" with 100 records containing <b>lastName =</b>
"<b>unassigned</b>", <b>firstName</b> <b>= </b>"", and <b>age = </b>"<b>0</b>".<br>
b) Input 10 last names, first names, and ages, and write them to the file.<br>
</page>
<page pagename="Exercise 14.11">
c) Update a record that has information in it, and if there is none tell the user
"No info".<br>
d) Delete a record that has information by reinitializing that particular record.<br>
<br>
<br>
</page>
<page pagename="Exercise 14.12">
<b>Exercise 14.12</b><br>
You are the owner of a hardware store and need to keep an inventory that can
tell you what different tools you have, how many of each you have on hand, and
the cost of each one. Write a program that initializes the random access file
"<b>hardware.dat</b>" to one hundred empty records, lets you input the data
concerning each tool, enables you to list all your tools, lets you delete a record
for a tool that you no longer have, and lets you update <i>any</i> information in the
file. The tool identification number should be the record number. Use the
following information to start your file:<br>
<foreign name="answers" url="^Answers::c:s0p7">
</page>
<page pagename="Exercise 14.12">
<img src="graphics/ch14/ex14012.gif" ><br>
<foreign name="answers" url="^Answers::c:s0p7">
</page>
<page pagename="Exercise 14.13">
<b>Exercise 14.13</b><br>
Modify the telephone number word generating program you wrote in Chapter 4
so that it writes its output to a file. This allows you to read the file at your
convenience. If you have a computerized dictionary available, modify your
program to look up the thousands of seven-letter words in the dictionary. Some
of the interesting seven-letter combinations created by this program may consist
of two or more words. For example, the phone number 8432677 produces
"<b>THEBOSS</b>." Modify your program to use the computerized dictionary to
check each possible seven-letter word to see if it is a valid one-letter word
followed by a valid six-letter word, a valid two-letter word followed by a valid
five-letter word, etc.<br>
<br>
</page>
<page pagename="Exercise 14.14">
<b>Exercise 14.14</b><br>
Write a program that uses the <b>sizeof</b> operator to determine the sizes in bytes of
the various data types on your computer system. Write the results to the file
"<b>datasize.dat</b>" so you may print the results later. The format for the results in
the file should be:<br>
<foreign name="answers" url="^Answers::c:s0p8">
</page>
<page pagename="Exercise 14.14">
<font size=2><br></font><font size=11><pre>
float 4<p>
double 8<p>
long double 16<p>
</pre></font>
Note: The sizes of the built-in data types on your computer may differ from
Composed of characters or bytes. <component type="drop" width=72 height=18 name="fields"> <br>
Used to retrieve information from a file. <component type="drop" width=72 height=18 name="key"> <br>
Composed of several fields. <component type="drop" width=72 height=18 name="record"> <br>
Smallest data item. <component type="drop" width=72 height=18 name="bit"> <br>
A group of related files. <component type="drop" width=72 height=18 name="database"> <br>
<component type=button name=b label="Check Your Answer" width=125 height=24>
</page>
</section>
<section type=Body name=Default title="14.3 Files and Streams">
<page>
<font size=18 bold>14.3 Files and Streams</font><hr>
C++ views each file simply as a sequence of bytes (<a href="^Illustration::c:s0p2">F<img src="bckgrnds/icons/ill_ico.gif" align=sidebar>ig.
14.2</a>). Each file ends either with an <i>end-of-file marker</i>
or at a specific byte number recorded in a system-
maintained, administrative data structure. When a file is
<i>opened</i>, an object is created and a stream is associated
with the object. In Chapter 11, we saw that four objects
are created for us automatically--<b>cin</b>, <b>cout</b>, <b>cerr</b>, and
<b>clog</b>. The streams associated with these objects provide
communication channels between a program and a
particular file or device. For example, the <b>cin</b> object
(standard input stream object) enables a program to <br>
</page>
<page>
input data from the keyboard, the <b>cout</b> object (standard
output stream object) enables a program to output data
to the screen, the <b>cerr</b> and <b>clog</b> objects (standard error
stream objects) enable a program to output error
messages to the screen.<br>
<spacer width=16 height=1>To perform file processing in C++, the header files
<b><iostream.h></b> and <b><fstream.h></b> must be included. The
header <b><fstream.h></b> includes the definitions for the
stream classes <b>ifstream</b> (for input from a file),
<b>ofstream</b> (for output to a file), and <b>fstream</b> (for input to
and output from a file). Files are opened by creating
objects of these stream classes. These stream classes are
derived from (i.e., inherit the functionality of) classes <br>
</page>
<page>
<b>istream</b>, <b>ostream</b>, and <b>iostream</b>, respectively. Thus,
the member functions, operators, and manipulators
described in Chapter 11, "C++ Stream Input/Output,"
can all be applied to file streams as well. The
inheritance relationships of the I/O classes discussed to
this point are summarized in<a href="^Illustration::c:s0p3"> <img src="bckgrnds/icons/ill_ico.gif" align=sidebar>Fig. 14.3</a>.<br>
</page>
</section>
<section type=Body name=Default title="14.4 Creating a Sequential Access File">
<page>
<font size=18 bold>14.4 Creating a Sequential Access File</font><hr>
C++ imposes no structure on a file. Thus, notions like
"record" do not exist in C++ files. Therefore, the
programmer must structure files to meet the
requirements of applications. In the following example,
we see how the programmer can impose a simple record
structure on a file. First we present the program, then
we analyze it in detail.<br>
<spacer width=16 height=1><a href="^Code::c:s0p0"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Figure 14.4</a> creates a simple sequential access file that
might be used in an accounts receivable system to help
manage the money owed by a company's credit clients.
For each client, the program obtains an account <br>
</page>
<page>
number, the client's name, and the client's balance (i.e.,
the amount the client still owes the company for goods
and services received in the past). The data obtained for
each client constitutes a record for that client. The
account number is used as the record key in this
application; that is, the file will be created and
maintained in account number order. This program
assumes the user enters the records in account number
order. In a comprehensive accounts receivable system, a
sorting capability would be provided so the user could
enter the records in any order--the records would then
be sorted and written to the file. <br>
</page>
<page>
Now let us examine this program. As stated previously,
files are opened by creating objects of stream classes
<b>ifstream</b>, <b>ofstream</b> or <b>fstream</b>. In <a href="^Code::c:s0p0"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.4</a>, the file is
to be opened for output, so an <b>ofstream</b> object is
created. Two arguments are passed to the object's
constructor--the <b>filename</b> and the <b>file open mode</b>. For
an <b>ofstream</b> object, the file open mode can be either
<b>ios::out </b>to output data to a file or <b>ios::app</b> to append
data to the end of a file (without modifying any data
already in the file). Existing files opened with mode
<b>ios::out</b> are <i>truncated</i>--all data in the file is discarded.
If the specified file does not yet exist, then a file is
on line 10 creates an <b>ofstream</b> object named
<b>outClientFile</b> associated with the file <b>clients.dat</b> that is
opened for output. The arguments "<b>clients.dat</b>" and
<b>ios::out</b> are passed to the <b>ofstream</b> <b><a href="^Errors::c:s0p1"><img src="bckgrnds/icons/cpe_ico.gif" align=sidebar></a></b>constructor which
opens the file. This establishes a "line of
communication" with the file. The arguments are
passed to the <b>ofstream</b> constructor function which
opens the file. By default, <b>ofstream</b> objects are opened
for <a href="^Errors::c:s0p0"><img src="bckgrnds/icons/cpe_ico.gif" align=sidebar></a>output, so the statement<br>
<font size=2><br></font><font size=11><pre>
ofstream outClientFile( "clients.dat" );<p>
</pre></font>
</page>
<page>
could have been used to open <b>clients.dat</b> for output.
<a href="^Illustration::c:s0p4"><img src="bckgrnds/icons/ill_ico.gif" align=sidebar>Figure 14.5</a> lists the file open modes. <br>
<spacer width=16 height=1><a href="^Errors::c:s0p2"><img src="bckgrnds/icons/cpe_ico.gif" align=sidebar></a>An <b>ofstream</b> object can be created without opening a
specific file--a file can be attached to the object later.
For example, the declaration<br>
<font size=2><br></font><font size=11><pre>
ofstream outClientFile;<p>
</pre></font>
creates <b>ofstream</b> object named <b>outClientFile</b>. The
<b>ofstream</b> member function <b>open</b> opens a file and
attaches it to an existing <b>ofstream</b> object as follows:<br>
<font size=2><br></font><font size=11><pre>
outClientFile.open( "clients.dat", ios::out );<p>
</pre></font>
After creating an <b>ofstream</b> object and attempting to
open it, the program tests whether the open operation <br>
</page>
<page>
was successful. The condition in the <b>if</b> structure at lines
12 through 15<br>
<font size=2><br></font><font size=11><pre>
if ( !outClientFile ) {<p>
cerr << "File could not be opened" << endl;<p>
exit( 1 );<p>
}<p>
</pre></font>
uses the overloaded <b>ios</b> operator member function
<b>operator!</b> to determine if the open operation
succeeded. The condition returns a nonzero (true) value
if either the <b>failbit</b> or <b>badbit</b> are set for the stream on
the <b>open</b> operation. Some possible errors are attempting
to open a nonexistent file for reading, attempting to <br>
</page>
<page>
open a file for reading without permission, and opening
a file for writing when no disk space is available. <br>
<spacer width=16 height=1>When the condition indicates that the open attempt was
unsuccessful, the error message "<b>File could not be
opened</b>" is output, and function <b>exit</b> is called to end the
program. The argument to <b>exit</b> is returned to the
environment from which the program was invoked.
Argument <b>0</b> indicates that the program terminated
normally; any other value indicates that the program
terminated due to an error. The value returned by <b>exit</b> is
used by the calling environment (most likely the
operating system) to respond appropriately to the error. <br>
</page>
<page>
Another overloaded <b>ios</b> operator member function--
<b>operator void*</b>--converts the stream to a pointer so it
can be tested as <b>0</b> (the null pointer) or nonzero (any
other pointer value). If the <b>failbit</b> or <b>badbit</b> (see
Chapter 11) have been set for the stream, <b>0</b> (false) is
returned. The condition in the following <b>while</b> header
(line 24) automatically invokes the <b>operator void*</b>
member function. <br>
<font size=2><br></font><font size=11><pre>
while ( cin >> account >> name >> balance )<p>
</pre></font>
The condition will remain <b>true</b> as long as neither the
<b>failbit</b> nor the <b>badbit</b> has been set for <b>cin</b>. Entering the
end-of-file indicator sets the <b>failbit</b> for <b>cin</b>. The
<b>operator void *</b> function can be used to test an input <br>
</page>
<page>
object for end-of-file instead of explicitly calling the
<b>eof</b> member function on the input object.<br>
<spacer width=16 height=1>If the file is opened successfully, the program begins
processing data. The following statement (lines 17 and
18) prompts the user to enter the various fields for each
record, or to enter end-of-file when data entry is
complete:<br>
<font size=2><br></font><font size=11><pre>
cout << "Enter the account, name, and balance.\n"<p>
<< "Enter EOF to end input.\n? ";<p>
</pre></font>
<a href="^Illustration::c:s0p5"><img src="bckgrnds/icons/ill_ico.gif" align=sidebar>Figure 14.6</a> lists the keyboard combinations for
entering end-of-file for various computer systems. <br>
<spacer width=16 height=1>Line 24 <br>
<font size=2><br></font><font size=11><pre>
while ( cin >> account >> name >> balance )<p>
</pre></font>
</page>
<page>
inputs each set of data and determines if end-of-file has
been entered. When end-of-file or bad data is entered,
the stream-extraction operation <b>>></b> on <b>cin</b> returns <b>0</b>
(normally this stream extraction returns <b>cin</b>) and the
<b>while</b> structure terminates. The user enters end-of-file
to inform the program that there is no more data to be
processed. The end-of-file indicator is set when the
end-of-file key combination is entered by the user. The
<b>while</b> structure continues looping as long as the end-of-
file indicator has not been entered. <br>
<spacer width=16 height=1>Lines 25 and 26<br>
<font size=2><br></font><font size=11><pre>
outClientFile << account << ' ' << name<p>
<< ' ' << balance << '\n';<p>
</pre></font>
</page>
<page>
write a set of data to the file "<b>clients.dat</b>" using the
stream-insertion operator <b><<</b> and the <b>outClientFile</b>
object associated with the file at the beginning of the
program. The data may be retrieved by a program
designed to read the file (see <a href="#s5p0">Section 14.5</a>). Note that
the file created in <a href="^Code::c:s0p0"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.4</a> is a text file. It can be read
by any text editor.<br>
<spacer width=16 height=1>Once the end-of-file indicator is entered, main
terminates. This causes the <b>outClientFile</b> object to be
destroyed thus invoking its destructor function which
closes the file <b>clients.dat</b>. <a href="^Perform::c:s0p0"><img src="bckgrnds/icons/perf_ico.gif" align=sidebar></a>An <b>ofstream</b> object can
explicitly be closed by the programmer using member
function <b>close</b> as follows:<br>
</page>
<page>
<font size=2><br></font><font size=11><pre>
outClientFile.close();<p>
</pre></font>
In the sample execution for the program of<a href="^Code::c:s0p0"> <img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.4</a>,
the user enters information for five accounts, and then
signals that data entry is complete by entering end-of-
file (^Z appears on screens of IBM PC compatibles).
This dialog window does not show how the data
records actually appear in the file. To verify that the file
has been created successfully, in the next section we
create a program to read the file and print its contents. <br>
</page>
</section>
<section type=Body name=Default title="14.5 Reading Data from a Sequential Access File">
<page>
<font size=18 bold>14.5 Reading Data from a Sequential Access
File</font><hr>
Data is stored in files so that it may be retrieved for
processing when needed. The previous section
demonstrated how to create a file for sequential access.
In this section, we discuss how to read data sequentially
from a file.<br>
<spacer width=16 height=1><a href="^Code::c:s0p1"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Figure 14.7</a> reads records from the file "<b>clients.dat</b>"
created by the program of <a href="^Code::c:s0p0"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.4</a> and prints the
contents of the records. Files are opened for input by
creating an <b>ifstream</b> class object. Two arguments are <br>
</page>
<page>
passed to the object--the filename and the file open
in line 13 creates an <b>ifstream</b> object called <b>inClientFile</b>
and associates with it the file <b>clients.dat</b> that is to be
opened for input. The arguments in parentheses are
passed to the <b>ifstream</b> constructor function which
opens the file and establishes a "line of
communication" with the file. <br>
<spacer width=16 height=1><a href="^Practice::c:s0p0"><img src="bckgrnds/icons/gpp_ico.gif" align=sidebar></a>Objects of class <b>ifstream</b> are opened for input by
default, so the statement<br>
<font size=2><br></font><font size=11><pre>
ifstream inClientFile( "clients.dat" );<p>
</pre></font>
</page>
<page>
could have been used to open <b>clients.dat</b> for input. Just
as with an <b>ofstream</b> object, an <b>ifstream</b> object can be
created without opening a specific file and a file can be
attached to it later. <br>
<spacer width=16 height=1>The program uses the condition <b>!inClientFile</b> to
determine whether the file was opened successfully
before attempting to retrieve data from the file. Line 27<br>
<font size=2><br></font><font size=11><pre>
while ( inClientFile >> account >> name >> balance )<p>
</pre></font>
reads a set of data (i.e., a record) from the file. After the
preceding line is executed the first time, <b>account</b> has
the value <b>100</b>, <b>name</b> has the value "<b>Jones"</b>, and
<b>balance</b> has the value <b>24.98</b>. Each time the line is <br>
</page>
<page>
executed, another record is read from the file into the
variables <b>account</b>, <b>name</b>, and <b>balance</b>. The records are
displayed using function <b>outputLine</b> which uses
parameterized stream manipulators to format the data
for display. When the end of the file has been reached,
the input sequence in the <b>while</b> structure returns <b>0</b>
(normally the stream <b>inClientFile</b> is returned), the file
is closed by the <b>ifstream</b> destructor function, and the
program terminates. <br>
<spacer width=16 height=1>To retrieve data sequentially from a file, programs
normally start reading from the beginning of the file,
and read all the data consecutively until the desired data
are found. It may be necessary to process the file <br>
</page>
<page>
sequentially several times (from the beginning of the
file) during the execution of a program. Both the
<b>istream</b> class and the <b>ostream</b> class provide member
functions for repositioning the<i> file position pointer</i> (the
byte number of the next byte in the file to be read or
written). These member functions are <b>seekg</b> ("seek
get") for the <b>istream</b> class and <b>seekp</b> ("seek put") for
the <b>ostream</b> class. Each <b>istream</b> object has a "get
pointer" that indicates the byte number in the file from
which the next input is to occur, and each <b>ostream</b>
object has a "put pointer" that indicates the byte number
in the file at which the next output is to be placed. The
statement<br>
</page>
<page>
<font size=2><br></font><font size=11><pre>
inClientFile.seekg( 0 );<p>
</pre></font>
repositions the file position pointer to the beginning of
the file (location <b>0</b>) attached to <b>inClientFile</b>. The
argument to <b>seekg</b> is normally a long integer. A
second argument can be specified to indicate the <i>seek
direction</i>. The seek direction can be <b>ios::beg</b> (the
default) for positioning relative to the beginning of a
stream, <b>ios::cur</b> for positioning relative to the current
position in a stream, and <b>ios::end</b> for positioning
relative to the end of a stream. The file position pointer
is an integer value that specifies the location in the file
as a number of bytes from the starting location of the
file (this is sometimes referred to as the <i>offset</i> from the <br>
</page>
<page>
beginning of the file). Some examples of positioning
the "get" file position pointer are:<br>
<font size=2><br></font><font size=11><pre>
// position to the nth byte of fileObject <p>
// assumes ios::beg<p>
fileObject.seekg( n );<p>
// position n bytes forward in fileObject<p>
fileObject.seekg( n, ios::cur );<p>
// position y bytes back from end of fileObject<p>
fileObject.seekg( y, ios::end );<p>
// position at end of fileObject<p>
fileObject.seekg( 0, ios::end );<p>
</pre></font>
The same operations can be performed with <b>ostream</b>
member function <b>seekp</b>. Member functions <b>tellg</b> and
<b>tellp</b> are provided to return the current locations of the <br>
</page>
<page>
"get" and "put" pointers, respectively. The following
statement assigns the "get" file position pointer value to
variable <b>location</b> of type <b>long</b>.<br>
<font size=2><br></font><font size=11><pre>
location = filObject.tellg();<p>
</pre></font>
<a href="^Code::c:s0p2"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Figure 14.8</a> enables a credit manager to display the
account information for those customers with zero
balances (i.e., customers who do not owe the company
any money), credit balances (i.e., customers to whom
the company owes money), and debit balances (i.e.,
customers who owe the company money for goods and
services received in the past). The program displays a
menu and allows the credit manager to enter one of
three options to obtain credit information. Option 1 <br>
</page>
<page>
produces a list of accounts with zero balances. Option 2
produces a list of accounts with credit balances. Option
3 produces a list of accounts with debit balances.
Option 4 terminates program execution. Entering an
invalid option simply displays the prompt to enter
another choice. A sample output is shown in Fig. 14.9.<br>
Data that is formatted and written to a sequential access
file as shown in<a href="#s4p0"> Section 14.4</a> cannot be modified
without the risk of destroying other data in the file. For
example, if the name "<b>White</b>" needed to be changed to
"<b>Worthington</b>", the old name cannot simply be
overwritten. The record for <b>White</b> was written to the
file as<br>
<font size=2><br></font><font size=11><pre>
300 White 0.00<p>
</pre></font>
If this record is rewritten beginning at the same location
in the file using the longer name, the record would be<br>
<font size=2><br></font><font size=11><pre>
300 Worthington 0.00<p>
</pre></font>
</page>
<page>
The new record contains six more characters than the
original record. Therefore, the characters beyond the
second "<b>o</b>" in "<b>Worthington</b>" would overwrite the
beginning of the next sequential record in the file. The
problem here is that in the formatted input/output model
using the insertion operator <b><<</b> and the extraction
operator <b>>></b>, fields--and hence records--can vary in
size. For example, 7, 14, 117, 2074, and 27383 are all
<b>int</b>s and each is stored in the same number of "raw
data" bytes internally, but when these integers are
output as formatted text to the screen or to a file on
disk, they become different-sized fields. Therefore, the <br>
</page>
<page>
formatted input/output model is not usually used to
update records in place.<br>
<spacer width=16 height=1>Such updating can be done, but it is awkward. For
example, to make the preceding name change, the
records before <b>300 White 0.00</b> in a sequential access
file could be copied to a new file, the updated record
would then be written to the new file, and the records
after <b>300 White 0.00</b> would be copied to the new file.
This requires processing every record in the file to
update one record. If many records are being updated in
one pass of the file, then this technique can be
acceptable.<br>
</page>
</section>
<section type=Body name=Default title="14.7 Random Access Files">
<page>
<font size=18 bold>14.7 Random Access Files</font><hr>
So far, we have seen how to create sequential access
files and to search through them to locate particular
information. Sequential access files are inappropriate
for so-called <i>"instant-access" applications</i> in which a
particular record of information must be located
immediately. Some popular instant access applications
are airline reservation systems, banking systems, point-
of-sale systems, automated teller machines and other
kinds of <i>transaction processing systems</i> that require
rapid access to specific data. The bank at which you
have your account may have hundreds of thousands or <br>
</page>
<page>
even millions of other customers, yet when you use an
automated teller machine, your account is checked for
sufficient funds in seconds. This kind of instant access
is possible with <i>random access files</i>. Individual records
of a random access file can be accessed directly (and
quickly) without searching through other records. <br>
<spacer width=16 height=1>As we have said, C++ does not impose structure on a
file. So the application that wants to use random access
files must literally create them. A variety of techniques
can be used to create random access files. Perhaps the
simplest is to require that all records in a file are of the
same fixed length. Using fixed length records makes it
easy for a program to calculate (as a function of the <br>
</page>
<page>
record size and the record key) the exact location of any
record relative to the beginning of the file. We will soon
see how this facilitates immediate access to specific
records, even in large files. <br>
<spacer width=16 height=1><a href="^Illustration::c:s0p6"><img src="bckgrnds/icons/ill_ico.gif" align=sidebar>Figure 14.10</a> illustrates C++'s view of a random access
file composed of fixed-length records (each record is
100 bytes long). A random access file is like a railroad
train with many cars--some empty and some with
contents. <br>
<spacer width=16 height=1>Data can be inserted in a random access file without
destroying other data in the file. Data stored previously
also can be updated or deleted without rewriting the
entire file. In the following sections we explain how to <br>
</page>
<page>
create a random access file, enter data, read the data
both sequentially and randomly, update the data, and
which always writes 4 bytes (on a machine with 4-byte
integers). The <b>write</b> function expects a first argument
of type <b>const char *</b>, hence we used the
<b>reinterpret_cast<const char *></b> cast operator to <br>
</page>
<page>
convert the address of <b>number</b> to a <b>const char *</b>
pointer. The second argument of <b>write</b> is an integer of
type <b>size_t</b> specifying the number of bytes to be
written. As we will see, <b>istream</b> function <b>read</b> can then
be used to read the 4 bytes back into integer variable
<b>number</b>. <br>
<spacer width=16 height=1>Random access file processing programs rarely write a
single field to a file. Normally, they write one <b>struct</b> or
<b>class</b> object at a time, as we show in the following
examples. <br>
<spacer width=16 height=1>Consider the following problem statement:<br>
<font size=6><br></font><indent width=16><font size=14><i>Create a credit processing program capable of storing up
to 100 fixed-length records for a company that can have </i></font></indent><font size=6><br></font>
</page>
<page>
<font size=6><br></font><indent width=16><font size=14><i>up to 100 customers. Each record should consist of an account number that will be used as the record key, a last
name, a first name, and a balance. The program should be
able to update an account, insert a new account, delete an
account, and list all the account records in a formatted
text file for printing.</i></font></indent><font size=6><br></font>
The next several sections introduce the techniques
necessary to create this credit processing program.
<a href="^Code::c:s0p3"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Figure 14.11</a> illustrates opening a random access file,
defining the record format using a <b>struct</b> (defined in
header file <b>clntdata.h</b>) and writing data to the disk. This
program initializes all 100 records of the file
"<b>credit.dat</b>" with empty <b>struct</b>s using function <b>write</b> <br>
</page>
<page>
(at lines 34 and 35). Each empty <b>struct</b> contains <b>0</b> for
the account number, the null string (represented by
empty quotation marks) for the last name, the null
string for the first name and <b>0.0</b> for the balance. The file
is initialized with the proper amount of empty space in
which the account data will be stored, and to determine
in subsequent programs if each record is empty or
contains data. <br>
<spacer width=16 height=1>In <a href="^Code::c:s0p3"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.11</a>, the statement at lines 34 through 36<br>
<component type=button name=b label="Check Your Answer" width=125 height=24>
</page>
</section>
<section type=Body name=Default title="14.9 Writing Data Randomly to a Random Access File">
<page>
<font size=18 bold>14.9 Writing Data Randomly to a Random
Access File</font><hr>
The program of <a href="^Code::c:s0p4"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.12</a> writes data to the file
"<b>credit.dat</b>". It uses the combination of <b>ostream</b>
functions <b>seekp</b> and <b>write</b> to store data at exact
locations in the file. Function <b>seekp</b> sets the "put" file
position pointer to a specific position in the file, then
<b>write</b> outputs the data. A sample execution is shown in
<a href="^Code::c:s0p4">F</a> <a href="^Code::c:s0p4"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>ig. 14.13</a>. Note that the program of <a href="^Code::c:s0p4"><img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig. 14.12</a>
includes the header file <b>clntdata<tt>.h</tt></b> defined in<a href="^Code::c:s0p3"> <img src="bckgrnds/icons/code_ico.gif" align=sidebar>Fig.
<indent width=8 delay>* Member functions <b>tellp</b> and <b>tellg</b> return the current
locations of the "put" and "get" pointers, respectively.</indent>
<indent width=8 delay>* A convenient way to implement random access files
is by using only fixed-length records. Using this technique, a program can quickly calculate the exact location of a record relative to the beginning of the file. </indent>
<indent width=8 delay>* Data can be inserted in a random access file without
destroying other data in the file. Data can be updated or
deleted without rewriting the entire file. </indent>
<indent width=8 delay>* The <b>ostream</b> member function <b>write</b> outputs to a
specified stream some number of bytes beginning at a
designated location in memory. When the stream is </indent>
</page>
<page>
<indent width=8 delay>* associated with a file, the data is written at the location
specified by the "put" file position pointer. </indent>
<indent width=8 delay>* The <b>istream</b> member function <b>read</b> inputs some
number of bytes from the specified stream to an area in
memory beginning with a designated address. The
bytes are input beginning at the location specified by
the "get" file position pointer. </indent>
<indent width=8 delay>* The <b>write</b> function expects a first argument of type
<b>const char*</b>, so this argument must be cast to <b>const
char*</b> if it is of some other pointer type. The second
argument is an integer that specifies the number of
bytes to be written. </indent>
<indent width=8 delay>* The compile-time, unary operator <b>sizeof</b> returns the </indent>
</page>
<page>
<indent width=8 delay>* size in bytes of the object contained in parentheses;
<b>sizeof</b> returns an unsigned integer. </indent>
<indent width=8 delay>* The <b>istream</b> member function <b>read</b> inputs a specified number of bytes from the designated stream into an
object; <b>read</b> requires a first argument of type <b>char*</b>. </indent>
<indent width=8 delay>* The <b>ios</b> member function <b>eof</b> determines if the end of
the file indicator has been set for the designated stream.
End-of-file is set after an attempted read fails.</indent>
</page>
<page>
<br>
</page>
<page>
</page>
</section>
<section type=Popup name=Debug title="Testing">
<page>
This chapter does not contain any Testing and Debugging tips.